package com.stylefeng.guns.modular.apple_app_manage.service.impl;

import com.stylefeng.guns.core.common.exception.BizExceptionEnum;
import com.stylefeng.guns.core.exception.GunsException;
import com.stylefeng.guns.core.shiro.ShiroKit;
import com.stylefeng.guns.core.util.CmdUtil;
import com.stylefeng.guns.modular.apple.properties.SftpProperties;
import com.stylefeng.guns.modular.apple.utils.AppUtil;
import com.stylefeng.guns.modular.apple.utils.FileUtil;
import com.stylefeng.guns.modular.apple_app_manage.entity.ApplicationDTO;
import com.stylefeng.guns.modular.apple_app_manage.model.Application;
import com.stylefeng.guns.modular.apple_app_manage.dao.ApplicationMapper;
import com.stylefeng.guns.modular.apple_app_manage.service.IApplicationService;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.stylefeng.guns.modular.domain_manage.dao.DomainInfoMapper;
import com.stylefeng.guns.modular.domain_manage.model.DomainInfo;
import com.stylefeng.guns.modular.domain_manage.service.IDomainInfoService;
import com.stylefeng.guns.utils.IpaUtils;
import org.apache.tomcat.util.http.fileupload.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 应用表 服务实现类
 * </p>
 *
 * @author GodRui
 * @since 2020-06-20
 */
@Service
public class ApplicationServiceImpl extends ServiceImpl<ApplicationMapper, Application> implements IApplicationService {

    private final Logger logger = LoggerFactory.getLogger(ApplicationServiceImpl.class);

    @Autowired
    private IDomainInfoService domainInfoService;

    @Autowired
    private DomainInfoMapper domainInfoMapper;

    @Resource(name = "imageSftp")
    private SftpProperties imageSftp;
    @Value("${ios-app.root-path}")
    private String appRootPath;
    @Value("${ios-app.ipa-name}")
    private String ipaName;
    @Value("${ios-app.api-domain}")
    private String apiDomain;

    // 添加应用
    @Transactional
    public void addNewApplication(ApplicationDTO app) {
        //Application extApp = baseMapper.getAppByAppName(app.getAppName());
//        if(extApp != null) {
//            throw new GunsException(BizExceptionEnum.APP_NAME_HAS_EXIST);
//        }
        // 生成appCode
        String appCode = AppUtil.genericAppCode(6);
        Application codeApp = baseMapper.getAppByAppCode(appCode);
        while (codeApp != null) {
            appCode = AppUtil.genericAppCode(6);
            codeApp = baseMapper.getAppByAppCode(appCode);
        }
        // 创建应用目录
        File newAppDir = new File(appRootPath + appCode);
        newAppDir.mkdir();
        // 上传ipa包到应用目录
        FileUtil.uploadFile(app.getIpaFile(),
                appCode + File.separator + ipaName,
                imageSftp);
        // 上传logo到图片目录
        FileUtil.uploadFile(app.getLogo(),
                appCode + File.separator + "icon.png",
                imageSftp);
        // 上传全图到图片目录
        FileUtil.uploadFile(app.getFsImage(),
                appCode + File.separator + "fsImage.png",
                imageSftp);
        // 解压ipa包并获取应用信息（版本，bundleId）
        String ipaPath = appRootPath
                + appCode + File.separator + ipaName;
        Map<String, Object> appInfo = null;
        try {
            appInfo = AppUtil.getInfoFromIpa(ipaPath);
        } catch (IOException e){
            logger.info("获取ipa信息错误：{}", e.getMessage());
        }
        // 获取包大小(M)
        File ipaFile = new File(ipaPath);
        double ipaSize =  ipaFile.length() / 1000.0 / 1000.0;
        ipaSize=(float)(Math.round(ipaSize*100.0)/100.0);
        // 修改并拷贝描述文件
        String targetProfilePath = appRootPath + appCode;
        String uploadDeviceInfoUrl = apiDomain + "/UDID/send?app=" + appCode;
        try {
            AppUtil.creatUDIDMobileconfig(app.getAppName(), uploadDeviceInfoUrl, targetProfilePath, appRootPath);
        } catch (IOException e){
            throw  new GunsException(BizExceptionEnum.UPLOAD_MOBILE_PROFILE_ERROR);
        }

        if (app.getSupportPush().equals(1)) {
            try {
                logger.info("hook 通知库 >> ipaPath: {}", appRootPath
                        + appCode + File.separator );

                IpaUtils.handleIpaPackage(appRootPath
                    + appCode + File.separator , appRootPath + "WJHookFrameWork.framework");
            } catch (IOException e){
                throw new GunsException(BizExceptionEnum.HANDLE_IPA_PUSHHOOK_ERROR);
            }
        }

        // 插入应用
        Application application = new Application();
        application.setAppCode(appCode);
        application.setAppName(app.getAppName());
        application.setAppAlias(app.getAppAlias());
        application.setAppDesc(app.getAppDesc());
        application.setBundleId((String)appInfo.get("bundle"));
        application.setAppPackagePath(ipaPath);
        application.setAppPlatform(1);
        application.setSupportPush(app.getSupportPush());
        application.setPackageSize((float)ipaSize);
        application.setUserId(ShiroKit.getUser().getId());
        application.setUserName(ShiroKit.getUser().getName());
        String versionString = (String)appInfo.get("version");
        if(versionString == null || versionString.length() == 0) {
            versionString = "1.0.0";
        }
        application.setAppVersion(versionString);

        // 获取一个可用的落地页域名
        DomainInfo toUseDomain =  domainInfoService.getOneAvailDomain();

        String webUrl = toUseDomain.getUrlName() + "?app=" + appCode;
        application.setAppUrl(webUrl);
        // 获取一个可用的资源域名
        List<DomainInfo> inUseDomains = domainInfoMapper.getInuseResourceDomain();
        if(inUseDomains == null || inUseDomains.size() == 0) {
            throw new GunsException(BizExceptionEnum.DOMAIN_IS_EXHAUST);
        }
        DomainInfo inUseDomain = inUseDomains.get(0);
        String logoUrl = inUseDomain.getUrlName()
                + File.separator + appCode + File.separator + "icon.png";
        application.setImage(logoUrl);
        String fsImageUrl = inUseDomain.getUrlName()
                + File.separator + appCode + File.separator + "fsImage.png";
        application.setFsImage(fsImageUrl);
        baseMapper.insert(application);
    }

    public void deleteApplicationById(Integer id) {

        Application application = baseMapper.selectById(id);
        String appCode = application.getAppCode();
        File appDir = new File(appRootPath + appCode);
        if(appDir.exists()) {
            try {
                FileUtils.deleteDirectory(appDir);
            } catch (IOException e){
                e.printStackTrace();
            }
        }
        super.deleteById(id);
    }

    public void updateApplicationById(Integer id, MultipartFile file) {
        Application application = baseMapper.selectById(id);
        String appCode = application.getAppCode();
        String ipaPath = appRootPath
                + appCode + File.separator + ipaName;
        String cacheIpaPath = appRootPath
                + appCode + File.separator + "iosCache.ipa";
        File ipaFile = new File(ipaPath);
        File cacheFile = new File(cacheIpaPath);
        // 重命名原始包
        if(ipaFile.exists()) {
            boolean res = ipaFile.renameTo(cacheFile);
            if(!res) {
                logger.info("重命名原始ipa包失败");
            }
        }
        // 上传ipa包到应用目录
        FileUtil.uploadFile(file,
                appCode + File.separator + ipaName,
                imageSftp);

        // 如果支持通知，注入通知静态库
        if(application.getSupportPush() == 1) {
            try {
                logger.info("hook 通知库 >> ipaPath: {}", appRootPath
                        + appCode + File.separator );
                IpaUtils.handleIpaPackage(appRootPath
                        + appCode + File.separator , appRootPath + "WJHookFrameWork.framework");
            } catch (IOException e){
                throw new GunsException(BizExceptionEnum.HANDLE_IPA_PUSHHOOK_ERROR);
            }
        }
        String versionStr = null;
        String bundleStr = null;
        try {
            Map<String, Object> info = AppUtil.getInfoFromIpa(ipaPath);
            versionStr = (String)info.get("version");
            bundleStr = (String)info.get("bundle");
        } catch (IOException e) {
            boolean res = cacheFile.renameTo(ipaFile);
            if (!res) {
                logger.info("备份文件重命名失败");
            }
            throw new GunsException(BizExceptionEnum.INFO_PLIST_READ_ERROR);
        }
        boolean delete = cacheFile.delete();
        if(!delete) {
            logger.info("删除备份文件失败");
        }
        application.setAppVersion(versionStr);
        application.setBundleId(bundleStr);

        double ipaSize =  ipaFile.length() / 1000.0 / 1000.0;
        ipaSize=(float)(Math.round(ipaSize*100.0)/100.0);
        application.setPackageSize((float)ipaSize);
        application.setCreateTime(new Date());
        baseMapper.updateById(application);

        // 遍历appCode目录下的多有appleAccount目录，重新签名后替换老包
        String updateScript = appRootPath + "updateIpa.rb";
        String result = CmdUtil.cmd("ruby " + updateScript + " " + appCode);
        logger.info("run {} result: {}", updateScript, result);
        if(result.equals("0")) {
            throw new GunsException(BizExceptionEnum.IPA_UPDATE_FAILED);
        }
    }

    @Override
    public void updateApplicationWithDomainName(String sourceDomain, String targetDomain) {
        logger.info("source: {}, target: {}", sourceDomain, targetDomain);
        baseMapper.updateAppWithDomain(sourceDomain, targetDomain);
    }

    @Override
    public void onOffApplicationById(Integer id){
        Application app = baseMapper.selectById(id);
        if(app == null) {
            throw new GunsException(BizExceptionEnum.APP_NOT_EXIST);
        }
        Integer nowStatus = app.getStatus();
        Integer toStatus = nowStatus == 1 ? 0: 1;
        app.setStatus(toStatus);
        baseMapper.updateById(app);
    }

    @Override
    public Object getAppNameList() {
        return this.baseMapper.findAppListByMerchantId(ShiroKit.getUser().getId());
    }
}
